package com.tiancheng.trade.settlement.service.settlement.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.tiancheng.trade.commom.core.data.PageInfo;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.settlement.bo.MerchantBO;
import com.tiancheng.trade.settlement.enums.OrderSourceEnum;
import com.tiancheng.trade.settlement.exception.BusinessException;
import com.tiancheng.trade.settlement.feign.MerchantPaymentChannelService;
import com.tiancheng.trade.settlement.mapper.settlement.StatementAccountMapper;
import com.tiancheng.trade.settlement.mapper.settlement.StatementProductMapper;
import com.tiancheng.trade.settlement.model.settlement.StatementAccount;
import com.tiancheng.trade.settlement.model.settlement.StatementProduct;
import com.tiancheng.trade.settlement.service.settlement.ISettlementBillResultService;
import com.tiancheng.trade.settlement.service.settlement.IStatementAccountService;
import com.tiancheng.trade.settlement.vo.settlement.admin.StatementAccountCreateVO;
import com.tiancheng.trade.settlement.vo.settlement.admin.StatementAccountQueryVO;
import com.tiancheng.trade.settlement.vo.settlement.admin.res.StatementProductResVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class StatementAccountService implements IStatementAccountService {

    @Autowired
    ISettlementBillResultService billResultService;

    @Autowired
    MerchantPaymentChannelService merchantService;

    @Autowired
    StatementAccountMapper accountMapper;

    @Autowired
    StatementProductMapper productMapper;

    @Override
    public StatementAccount findById(Long id) {
        StatementAccount statementAccount = accountMapper.selectById(id);
        if (null != statementAccount) {
            QueryWrapper<StatementProduct> conditions = new QueryWrapper<StatementProduct>();
            conditions.eq("is_delete", "0");
            conditions.eq("statement_code", statementAccount.getStatementCode());
            List<StatementProduct> productList = productMapper.selectList(conditions);
            statementAccount.setProductList(productList);
        }
        return statementAccount;
    }

    @Override
    public PageInfo<StatementAccount> getStatementAccountPage(StatementAccountQueryVO accountQueryVO) {
        QueryWrapper<StatementAccount> conditions = new QueryWrapper<>();
        conditions.eq("is_delete", false);

        if (StringUtils.isNotBlank(accountQueryVO.getMerchantName())) {
            conditions.like("merchant_name", accountQueryVO.getMerchantName());
        }
        if (StringUtils.isNotBlank(accountQueryVO.getCityName())) {
            conditions.eq("city_name", accountQueryVO.getCityName());
        }
        if (StringUtils.isNotBlank(accountQueryVO.getOrderSource())) {
            conditions.eq("order_source", accountQueryVO.getOrderSource());
        }
        if (null != accountQueryVO.getCountStartDate()) {
            conditions.ge("count_start_date", accountQueryVO.getCountStartDate() + " 00:00:00");
        }
        if (null != accountQueryVO.getCountEndDate()) {
            conditions.le("count_end_date", accountQueryVO.getCountEndDate() + " 23:59:59");
        }
        if (null != accountQueryVO.getCreatedStartDt()) {
            conditions.ge("created_dt", accountQueryVO.getCreatedStartDt() + " 00:00:00");
        }
        if (null != accountQueryVO.getCreatedEndDt()) {
            conditions.le("created_dt", accountQueryVO.getCreatedEndDt() + " 23:59:59");
        }
        conditions.orderByDesc("created_dt");
        PageInfo<StatementAccount> pageInfo = accountMapper.find(conditions, accountQueryVO.getCurrentPage(), accountQueryVO.getPageSize());
        if (CollectionUtils.isNotEmpty(pageInfo.getList())) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            List<StatementAccount> list = pageInfo.getList();
            list.forEach(a -> {
                a.setOrderSource(OrderSourceEnum.getDesc(a.getOrderSource()));
                a.setCountStartDateStr(df.format(a.getCountStartDate()));
                a.setCountEndDateStr(df.format(a.getCountEndDate()));
            });
        }
        return pageInfo;
    }

    @Override
    public List<StatementAccount> getStatementAccountList(StatementAccountQueryVO accountQueryVO) {
        QueryWrapper<StatementAccount> conditions = new QueryWrapper<>();
        conditions.eq("is_delete", false);

        if (StringUtils.isNotBlank(accountQueryVO.getMerchantCode())) {
            conditions.eq("merchant_code", accountQueryVO.getMerchantCode());
        }
        if (StringUtils.isNotBlank(accountQueryVO.getOrderSource())) {
            conditions.eq("order_source", accountQueryVO.getOrderSource());
        }
        if (null != accountQueryVO.getCountStartDate()) {
            conditions.ge("count_start_date", accountQueryVO.getCountStartDate() + " 00:00:00");
        }
        if (null != accountQueryVO.getCountEndDate()) {
            conditions.le("count_end_date", accountQueryVO.getCountEndDate() + " 23:59:59");
        }
        List<StatementAccount> list = accountMapper.selectList(conditions);
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addStatementAccount(StatementAccountCreateVO createVO) throws BusinessException {
        //先统计需生成对账函的商户信息
        List<StatementProductResVO> list = billResultService.queryStatementAccount(createVO);
        if (CollectionUtils.isEmpty(list)) {
            return 0;
        }
        //获取商户编号集合
        List<String> listStr = list.stream().map(StatementProductResVO::getMerchantCode).collect(Collectors.toList());
        List<String> listStr1 = listStr.stream().distinct().collect(Collectors.toList());
        //先统计需生成对账函的商户中包含的产品信息
        createVO.setMerchantCodeList(listStr1);
        List<StatementProductResVO> productResList = billResultService.queryStatementProduct(createVO);

//        //获取产品编号集合
//        List<String> proList = productResList.stream().map(StatementProductResVO::getProductCode).collect(Collectors.toList());

        Map<String, MerchantBO> merchantMap = new HashMap<String, MerchantBO>();
//        Map<String, ProductBO> productMap = new HashMap<String, ProductBO>();
        //按商户取商户城市信息
        Result<List<MerchantBO>> merchantBOList = merchantService.getMerchantByMerCode(listStr1);
        if (merchantBOList.getRet() == 0) {
            List<MerchantBO> merchantList = merchantBOList.getData();
            merchantMap = merchantList.stream().collect(Collectors.toMap(MerchantBO::getMerchantCode, Function.identity(), (k1, k2) -> k2));
        }
//        //按商户取产品单价信息
//        Result<List<ProductBO>> productBOList = merchantService.getProductByProductCode(proList);
//        if (productBOList.getRet() == 0) {
//            List<ProductBO> productList = productBOList.getData();
//            productMap = productList.stream().collect(Collectors.toMap(ProductBO::getProductCode, Function.identity(), (k1, k2) -> k2));
//        }
        List<StatementAccount> accountList = new ArrayList<StatementAccount>();
        List<StatementProduct> productList = new ArrayList<StatementProduct>();
        log.info("新增对账函，日志打印");
        for (StatementProductResVO statementList : list) {
            StatementAccount account = new StatementAccount();
            String content = statementList.getMerchantCode() + String.valueOf(LocalDateTime.now()).substring(0, 19);
            String statementCode = (DigestUtils.md5DigestAsHex(content.getBytes()).toUpperCase());
            account.setStatementCode(statementCode);
            account.setMerchantCode(statementList.getMerchantCode());
            if (0 != merchantMap.size()) {
                MerchantBO merchant = merchantMap.get(statementList.getMerchantCode());
                if (null != merchant) {
                    account.setMerchantName(merchant.getMerchantName());
                    account.setCityName(merchant.getCityName());
                }
            }
            createVO.setCountStartDate(createVO.getCountStartDate() + " 00:00:00");
            createVO.setCountEndDate(createVO.getCountEndDate() + " 23:59:59");
            log.info("createVO.getCountStartDate().........{}", createVO.getCountStartDate());
            log.info("createVO.getCountEndDate().........{}", createVO.getCountEndDate());
            if (StringUtils.isNotBlank(createVO.getCountStartDate()) &&
                    createVO.getCountStartDate().length() > 19) {
                createVO.setCountStartDate(createVO.getCountStartDate().substring(0, 19));
            }
            if (StringUtils.isNotBlank(createVO.getCountEndDate()) &&
                    createVO.getCountEndDate().length() > 19) {
                createVO.setCountEndDate(createVO.getCountEndDate().substring(0, 19));
            }
            LocalDateTime countStartDate = LocalDateTime.parse(createVO.getCountStartDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            LocalDateTime countEndDate = LocalDateTime.parse(createVO.getCountEndDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            account.setCountStartDate(countStartDate);
            account.setCountEndDate(countEndDate);
            account.setOrderSource(createVO.getOrderSource());
            List<StatementProductResVO> filterList = productResList.stream().filter(product -> product.getMerchantCode().equals(statementList.getMerchantCode())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(filterList)) {
                for (StatementProductResVO productResVO : filterList) {
                    StatementProduct statementProduct = new StatementProduct();
                    statementProduct.setStatementCode(statementCode);
                    statementProduct.setProductCode(productResVO.getProductCode());
                    statementProduct.setProductName(productResVO.getProductName());
                    statementProduct.setSellQty(productResVO.getSellQty());
                    statementProduct.setSettlePrice(productResVO.getSettlePrice());
                    if (null != productResVO.getSettlePrice() && null != productResVO.getSellQty()) {
                        statementProduct.setSettleAmount(productResVO.getSellQty() * productResVO.getSettlePrice());
                    } else {
                        statementProduct.setSettleAmount(0);
                    }
                    productList.add(statementProduct);
                }
                account.setSettlePriceSum(filterList.stream().collect(Collectors.summingInt(StatementProductResVO::getSettlePrice)));
                account.setSellQtySum(filterList.stream().collect(Collectors.summingInt(StatementProductResVO::getSellQty)));
                account.setSettleAmountSum(filterList.stream().collect(Collectors.summingInt(StatementProductResVO::getSettleAmount)));
            }
            accountList.add(account);
        }
        log.info("新增对账函，保存数据");
        accountMapper.batchSaveStatementAccount(accountList);
        if (CollectionUtils.isNotEmpty(productList)) {
            productMapper.batchSaveStatementProduct(productList);
        }
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteStatementAccount(List<String> codeList) throws BusinessException {
        productMapper.deleteProductByStatementCode(codeList);
        return accountMapper.batchDelStatementAccount(codeList);
    }

    @Override
    public StatementAccount findByStatementCode(String statementCode) {
        QueryWrapper<StatementAccount> conditions = new QueryWrapper<>();
        conditions.eq("is_delete", false);
        conditions.eq("statement_code", statementCode);
        StatementAccount statementAccount = accountMapper.selectOne(conditions);
        if (null != statementAccount) {
            QueryWrapper<StatementProduct> productQueryWrapper = new QueryWrapper<StatementProduct>();
            productQueryWrapper.eq("is_delete", "0");
            productQueryWrapper.eq("statement_code", statementCode);
            List<StatementProduct> productList = productMapper.selectList(productQueryWrapper);
            statementAccount.setProductList(productList);
        }
        return statementAccount;
    }

    @Override
    public void statementAccountPdf(String statementCode, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 第一步：实例化一个document对象
        Document document = new Document();

        // 第二步：设置要到出的路径
//        FileOutputStream out = new FileOutputStream(reportPath + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()).toString() + ".pdf");

        //如果是浏览器通过request请求需要在浏览器中输出则使用下面方式
        OutputStream out = response.getOutputStream();

        // 第三步：设置字符 jar包中的字体格式
        // BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);

        //前端无法使用jar包中字体格式，只能按字体文件来设置
        String path = "http://yyn-static-resources-1254950508.file.myqcloud.com/fonts/simsun.ttc";
        BaseFont bfChinese = BaseFont.createFont(path + ",0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        // 第四步：标题字体样式
        Font fontZH1 = new Font(bfChinese, 18.0F, 1);       // 主标题
        Font fontZH2 = new Font(bfChinese, 12.0F, 1);       // 副标题
        Font fontZH3 = new Font(bfChinese, 12.0F, 1);       // 内容
        // 第五步，将pdf文件输出到磁盘
        PdfWriter writer = PdfWriter.getInstance(document, out);

        // 第六步，打开生成的pdf文件
        document.open();

        StatementAccount statementAccount = this.findByStatementCode(statementCode);

        // 第七步,设置内容
        String title1 = "                       对账函";
        String title2 = statementAccount.getMerchantName();
        String title3 = "    现将贵公司" + statementAccount.getCountStartDate().getYear() + "年" + statementAccount.getCountStartDate().getMonthValue() + "月" + statementAccount.getCountStartDate().getDayOfMonth() + "日" + "0时" + "至" + statementAccount.getCountEndDate().getYear() + "年" + statementAccount.getCountEndDate().getMonthValue() + "月" + statementAccount.getCountEndDate().getDayOfMonth() + "日" + "24时" + "在本公司服务平台的交易及结算信息反馈如";
        String title4 = "下,本公司经核对信息无误,烦请核对,盼回复为谢.";
        document.add(new Paragraph("\n"));
        document.add(new Paragraph(new Chunk(title1, fontZH1).setLocalDestination(title1)));
        document.add(new Paragraph("\n"));
        document.add(new Paragraph(new Chunk(title2, fontZH2).setLocalDestination(title2)));
        document.add(new Paragraph("\n"));
        document.add(new Paragraph(new Chunk(title3, fontZH2).setLocalDestination(title3)));
        document.add(new Paragraph(new Chunk(title4, fontZH2).setLocalDestination(title4)));

        // 创建table,注意这里的4是两列的意思,下面通过table.addCell添加的时候必须添加整行内容的所有列
        PdfPTable table1 = new PdfPTable(4);

        table1.setWidthPercentage(100.0F);
        table1.setHeaderRows(1);
        table1.getDefaultCell().setHorizontalAlignment(1);

        table1.addCell(new Paragraph("产品", fontZH3));
        table1.addCell(new Paragraph("销售数量", fontZH3));
        table1.addCell(new Paragraph("结算单价", fontZH3));
        table1.addCell(new Paragraph("结算金额", fontZH3));
        List<StatementProduct> list = statementAccount.getProductList();
        BigDecimal bigNum = new BigDecimal("100");
        Integer qty = 0;
        Integer price = 0;
        Integer amount = 0;
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(a -> {
                table1.addCell(new Paragraph(a.getProductName(), fontZH3));
                table1.addCell(new Paragraph(a.getSellQty().toString(), fontZH3));
                if (null != a.getSettlePrice()) {
                    table1.addCell(new Paragraph(new BigDecimal(a.getSettlePrice()).divide(bigNum).toString(), fontZH3));
                }
                if (null != a.getSettlePrice()) {
                    table1.addCell(new Paragraph(new BigDecimal(a.getSettleAmount()).divide(bigNum).toString(), fontZH3));
                }
            });
            qty = list.stream().collect(Collectors.summingInt(StatementProduct::getSellQty));
            price = list.stream().collect(Collectors.summingInt(StatementProduct::getSettlePrice));
            amount = list.stream().collect(Collectors.summingInt(StatementProduct::getSettleAmount));
        }
        table1.addCell(new Paragraph("合计", fontZH3));
        table1.addCell(new Paragraph(qty.toString(), fontZH3));
        table1.addCell(new Paragraph(new BigDecimal(price).divide(bigNum).toString(), fontZH3));
        table1.addCell(new Paragraph(new BigDecimal(amount).divide(bigNum).toString(), fontZH3));
        document.add(new Paragraph("\n"));
        document.add(table1);
        document.add(new Paragraph("\n" + "\n" + "\n" + "\n" + "\n"));
        String title5 = "                                                               云南腾云信息产业有限公司";
        String title6 = "                                                                             " + statementAccount.getCreatedDt().toLocalDate();
        String title7 = "   结算信息如上,请核对,并将核对信息填入下方信息核对栏";
        document.add(new Paragraph("\n"));
        document.add(new Paragraph(new Chunk(title5, fontZH2).setLocalDestination(title5)));
        document.add(new Paragraph(new Chunk(title6, fontZH2).setLocalDestination(title6)));
        document.add(new Paragraph("\n"));
        document.add(new Paragraph(new Chunk(title7, fontZH2).setLocalDestination(title7)));
        document.add(new Paragraph("\n"));
        document.add(new Paragraph("\n"));
//
//        String title8 = "信息核对不符                                        信息核对相符";
//        String title9 = "我方实际金额(详见附表)：                            ";
//        String title10 = "单位名称_______________                             单位名称";
//        String title11 = "确认人:                                             确认人:";
//        document.add(new Paragraph(new Chunk(title8, fontZH2).setLocalDestination(title8)));
//        document.add(new Paragraph(new Chunk(title9, fontZH2).setLocalDestination(title9)));
//        document.add(new Paragraph(new Chunk(title10, fontZH2).setLocalDestination(title10)));
//        document.add(new Paragraph(new Chunk(title11, fontZH2).setLocalDestination(title11)));

        // 创建table,注意这里的4是两列的意思,下面通过table.addCell添加的时候必须添加整行内容的所有列
        PdfPTable table2 = new PdfPTable(2);

        table2.setWidthPercentage(100.0F);
        table2.addCell(new Paragraph("信息核对不符" + "\n" + "\n" + "我方实际金额(详见附表)：" + "\n" + "\n" + "单位名称_______________" + "\n" + "\n" + "确认人:" + "\n" + "\n", fontZH2));
        table2.addCell(new Paragraph("信息核对相符" + "\n" + "\n" + "\n" + "单位名称" + "\n" + "\n" + "确认人:" + "\n" + "\n", fontZH2));
        document.add(table2);

        // 第八步，关闭document
        document.close();

        System.out.println("导出pdf成功~");
    }

}
